package com.itheima.aspect;

import com.itheima.pojo.Emp;
import com.itheima.pojo.Logging;
import com.itheima.service.EmployeeService;
import com.itheima.service.LogService;
import com.itheima.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class ControllerLogAspect {
    @Autowired
    private EmployeeService employeeService;
    // 定义切点：拦截所有Controller包下的方法
    @Autowired
    private LogService logService;
    @Pointcut("execution(* com.itheima.controller..*.*(..)) && " +
            "!execution(* com.itheima.controller.UserController.*(..))")
    public void controllerPointcut() {}
    @Around("controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();

        // 获取请求头中的token
        String token = request.getHeader("token");
        if (token == null) {
            token = request.getHeader("token");
        }
        // 解析token
        Claims claims = JwtUtil.parseJWT("Nintendo_2024_9_26", token);
        Integer empId = null;
        if(claims.get("USER_ID")!=null){
            empId = (Integer) claims.get("USER_ID");
        };

        Emp emp = employeeService.findEmpById(empId==null?2:empId);
        // 获取请求参数
        Map<String, Object> params = new HashMap<>();
        Enumeration<String> paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            params.put(paramName, request.getParameter(paramName));
        }

        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        String[] argNames = signature.getParameterNames();
        Map<String, Object> methodParams = new HashMap<>();
        for (int i = 0; i < args.length; i++) {
            methodParams.put(argNames[i], args[i]);
        }

        // 记录请求信息
        System.out.println("======= 请求开始 =======");
        System.out.println("请求URL: {}"+ request.getRequestURL().toString());
        System.out.println("请求方式: {}"+request.getMethod());
        System.out.println("Token: {}"+token);
        System.out.println("类名: {}"+ className);
        System.out.println("方法名: {}"+methodName);
        System.out.println("请求参数: {}"+ params);
        System.out.println("方法参数: {}"+ methodParams);

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        // 执行方法
        Object result;
        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            System.out.println("异常信息: {}"+ throwable.getMessage());
            throw throwable;
        }

        // 记录结束时间
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;

        // 记录响应信息
        System.out.println("返回值: {}"+ result);
        System.out.println("耗时: {} ms"+costTime);
        System.out.println("======= 请求结束 =======");
        Logging logging = new Logging();
        logging.setClassName(className);
        logging.setMethodName(methodName);
        logging.setMethodParams(Arrays.toString(methodParams.entrySet().toArray()));
        logging.setOperateEmpId(empId);
        logging.setOperateEmpName(emp.getName());
        // 返回值简化一下
        String returnValue = result.toString();
        if (returnValue.length() > 100) {
            logging.setReturnValue(returnValue.substring(0, 100));
        } else {
            logging.setReturnValue(returnValue);
        }
        logging.setCostTime((int) costTime);
        logging.setOperateTime(LocalDateTime.now());
        logService.saveLog(logging);
        return result;
    }
}